/******************************************************************************/
//	AppCore.cpp	-	Controls all aspects of the program
//						(Entry, Rendering, Updates)
//
//	Author:		Russell Klinkerman
//	Created:	02.24.2004			Updated: 12.02.04
/******************************************************************************/

#include "AppCore.h"
#include "resource.h"

#include <stdio.h>
#include <stdlib.h>
#include <ctime>

// The instance of this class;
CAppCore	appCore;

// Include all needed components
#include "KlinkTimer.h"
#include "InputManager.h"
#include "EventFactory.h"

// Defines/Macros
#define	APPTITLE		"FSM Project"		//	Window Class & Application Name.

#define WINDOW_WIDTH	640			//	Window Width.
#define WINDOW_HEIGHT	480			//	Window Height.
#define FULLSCREEN		false		//	Screen Mode

// Uncomment the following line to have a console window.
//#pragma comment(linker, "/SUBSYSTEM:CONSOLE")

// Functions
void	CAppCore::Init()
{
	// Basic Members
	m_nWidth		=	WINDOW_WIDTH;
	m_nHeight		=	WINDOW_HEIGHT;
	m_bFullScreen	=	FULLSCREEN;

	// Managers
	d3dManager.Init();
	inputManager.Init();

	// Entities
	m_ChunLi.Init();

	// GUI
	dxiAppTitle.Load("bin\\title.tga", D3DCOLOR_XRGB(255,0,255));
	D3DXMatrixIdentity(&mAppTitle);
	D3DXMatrixTranslation(&mAppTitle, 300.0f, 325.0f, 0.0f);
}

bool	CAppCore::Update()
{
	CKlinkTimer::Update();	// Update timer services

	// Update DI Keyboard
	inputManager.ProcessKeyboard();

	// Update Entities
	m_ChunLi.Update();

	// Upon Success...
	return true;
}

void	CAppCore::Draw()
{
	// Clear back buffer
	d3dManager.Clear();

	// Draw 2D
	d3dManager.BeginSprites();
		m_ChunLi.Draw();		// Note: All actor draws must be called within BeginSprites() & EndSprites()
		d3dManager.Sprite(dxiAppTitle.GetTexture(), &mAppTitle);
	d3dManager.EndSprites();

	// Draw Text
	char szBuffer[64];
	sprintf(szBuffer, "Events Created: %d", Event::s_nEventsNewed);
	d3dManager.Text(szBuffer, 10, 10);

	sprintf(szBuffer, "Events Queued: %d", m_ChunLi.stateMachine.GetEventQueueSize());
	d3dManager.Text(szBuffer, 10, 30);

	// Swap Buffers
	d3dManager.Show();
}

void	CAppCore::Shutdown()
{
	m_ChunLi.Shutdown();

	d3dManager.Shutdown();
}

/******************************************************************************/
//	WinMain	-	Entry point of application
/******************************************************************************/
int WINAPI WinMain(	HINSTANCE hinstance, HINSTANCE hprevinstance, LPSTR lpcmdline, int ncmdshow)
{
	WNDCLASSEX	winClassEx;		//	This will hold the class we create
	MSG			msg;			//	Generic message
	HWND		hMainWnd;		//	The Main Window Handle.

	//	First fill in the window class stucture
	memset( &winClassEx, 0, sizeof(WNDCLASSEX) );

	winClassEx.cbSize			= sizeof(WNDCLASSEX); // Always set to size of WNDCLASSEX
    winClassEx.style			= CS_HREDRAW | CS_VREDRAW;
    winClassEx.lpfnWndProc		= WindowProc;
    winClassEx.hInstance		= hinstance;
    winClassEx.hbrBackground	= (HBRUSH)GetStockObject(WHITE_BRUSH);
	winClassEx.lpszClassName	= APPTITLE;
	winClassEx.hCursor			= (HCURSOR)LoadImage(NULL, MAKEINTRESOURCE(IDC_ARROW),
											IMAGE_CURSOR, 0, 0, LR_SHARED);

	if( !RegisterClassEx(&winClassEx) )	// Attempt To Register The Window Class
	{
		// If Class Registration has failed...
		MessageBox(NULL,"Failed To Register The Window Class.","ERROR",MB_OK|MB_ICONEXCLAMATION);
		return false;
	}

	//	Seed random numbers
	srand( (unsigned int)time(0) );

	//	Specify the Height & Window of our client rectangle.
	RECT	rClient	=	{ 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT };

	// This is our extended window style
	DWORD winStyleEx	= WS_EX_CLIENTEDGE; 
	DWORD winStyle		= WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX;

	// Adjusts the client rectangle, so when the window is created, the client rectangle
	// remains the size we want it to be. (Making room for Windows Stuff)
	AdjustWindowRectEx(&rClient, winStyle, false, winStyleEx);

	//	Create the window
	if (!(hMainWnd = CreateWindowEx(winStyleEx,
					      APPTITLE,
						  APPTITLE,
						  winStyle,
						  CW_USEDEFAULT,
						  CW_USEDEFAULT,
						  rClient.right - rClient.left, // Window Width
						  rClient.bottom - rClient.top, // Window Height
						  NULL,
						  NULL,
						  hinstance,
						  NULL)))
		return(0);

	// Tell OS to show our window and send it the first update.
	ShowWindow(hMainWnd, SW_SHOWDEFAULT); 
	UpdateWindow(hMainWnd); 

	// Using Timers, so sync.
	timeBeginPeriod(0);

	// Set App Vitals.
	appCore.SetWnd(hMainWnd);
	appCore.SetInstance(hinstance);

	// Initialize Application
	appCore.Init();

	//	Enter main event loop
	while(1)
	{
		if (PeekMessage(&msg,NULL,0,0,PM_REMOVE))
		{ 
			//	Test if this is a quit message
			if (msg.message == WM_QUIT)
				break;

			//	Translate any accelerator keys
			TranslateMessage(&msg);

			//	Send the message to the window proc
			DispatchMessage(&msg);

		}
		
		// Call Updates
		if(!appCore.Update() || (GetAsyncKeyState(VK_ESCAPE) && GetAsyncKeyState(VK_MENU)))
			break;

		// Draw
		appCore.Draw();
	}

	// Shutdown Application
	appCore.Shutdown();

	// End Timer
	timeEndPeriod(0);
	
	UnregisterClass(APPTITLE,hinstance);

	//	Return to Windows like this
	return (int)(msg.wParam);
}

int main(int argc, char ** argv)
{
	WinMain(GetModuleHandle(argv[0]), NULL, GetCommandLine(), SW_SHOW);
}

// WindowProc
LRESULT CALLBACK WindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
	//	This is the main message handler of the system

	//	What is the message 
	switch(msg)
	{
		case WM_CLOSE:
		case WM_DESTROY: 
		{
			//	Kill the application			
			PostQuitMessage(0);
		}
		break;

		default:
		{
			//	Process any messages that we didn't take care of 
			return (DefWindowProc(hwnd, msg, wparam, lparam));
		}
	}

	// 0 = Success
	return 0;
}